package com.example.dingtalklogin.common.config;

import com.example.dingtalklogin.common.exception.CheckException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

@ControllerAdvice
public class GlobalExceptionConfig {
    /**
     * 方法验证失败抛出异常
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    ResponseEntity<?> handleBindException(BindException e) {
        return ResponseEntity.status(HttpStatus.CONFLICT)
                .body(new ExceptionResponse(10001,e.getAllErrors().get(0).getDefaultMessage()));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    ResponseEntity<?> methodException(MethodArgumentNotValidException e) {
        StringBuilder builder = new StringBuilder();
        BindingResult bindingResult = e.getBindingResult();
        bindingResult.getAllErrors().forEach(o -> {
            builder.append(o.getDefaultMessage() + ",");
        });
        return ResponseEntity.badRequest().body(
                new ExceptionResponse(10001, builder.toString()));
    }

    /**
     * 自定义IValidate验证异常捕获
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    ResponseEntity<?> handleConstraintViolationException(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();

        StringBuilder errorMsgBuilder = new StringBuilder();
        for (ConstraintViolation cvl : constraintViolations) {
            errorMsgBuilder.append(cvl.getMessageTemplate()+";");
        }
        return ResponseEntity.status(HttpStatus.CONFLICT).body(new ExceptionResponse(10001, errorMsgBuilder.toString()));
    }

    /**
     * 409异常，验证失败
     */
    @ExceptionHandler(CheckException.class)
    @ResponseBody
    ResponseEntity<ExceptionResponse> checkExceptionHandler(CheckException e) {
        return ResponseEntity.status(HttpStatus.CONFLICT)
                .body(new ExceptionResponse(e.getCode(),e.getMessage()));
    }

    /**
     * 默认异常处理, 超出范围的应该重点关注, 可以钉钉通知等多途径来解决问题
     * @param throwable
     * @return
     */
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    ResponseEntity<?> defaultException(Throwable throwable){
        // TODO default异常，这个是超出想象的异常，可以根据需要添加一些监控代码
        // 这里打印日常，结合日志收集，可以在日志收集服务中预警
        throwable.printStackTrace();
        return ResponseEntity.status(HttpStatus.CONFLICT)
                .body(new ExceptionResponse(10001,throwable.getMessage()));
    }

    @AllArgsConstructor
    @Getter
    public static class ExceptionResponse{
        private Integer code;
        private String message;
    }

}
